package com.queue;

/**
 * 循环队列
 */
public class LoopQueue<E> implements Queue<E> {
    private E []data;
    private int front, tail;
    private int size;

    public LoopQueue(){
        data = (E[]) new Object[11];
    }

    public LoopQueue(int capacity){
        data = (E[]) new Object[capacity + 1];
    }

    /**
     * 获取容量
     * @return
     */
    public int getCapacity(){
        return data.length - 1;
    }
    @Override
    public int getSize() {
        return size;
    }

    @Override
    public boolean isEmpty() {
        return front == tail;
    }

    @Override
    public void enQueue(E e) {
        if((tail + 1) % data.length == front)
            resize(getCapacity() * 2);

        data[tail] = e;
        tail = (tail + 1) % data.length;
        size++;
    }

    @Override
    public E deQueue() {
        if(front == tail)
            throw new IllegalArgumentException("cannot dequeue from a empty queue");

        E res = data[front];
        data[front] = null;
        front = (front + 1) % data.length;
        size--;

        if(size == getCapacity() / 4 && getCapacity() / 2 != 0)
            resize(getCapacity()/2);
        return res;
    }

    @Override
    public E getFront() {
        if(isEmpty())
            throw new IllegalArgumentException("queue is empty");
        return data[front];
    }

    private void resize(int capacity){
        E[] newData = (E[]) new Object[capacity + 1];

        for(int i = 0; i < size; i++)
            newData[i] = data[(front + i) % data.length];

        data = newData;
        front = 0;
        tail = size;
    }

    @Override
    public String toString() {
        StringBuffer sb = new StringBuffer();
        sb.append(String.format("queue: size = %d , capacity = %d \n", size, getCapacity()));
        sb.append("[");

        for(int i = front; i != tail; i = (i + 1) % data.length){
            sb.append(data[i]);
            if((i+1) % data.length != tail)
                sb.append(",");
        }
        sb.append("]");
        return sb.toString();
        
    }
}
